home *** CD-ROM | disk | FTP | other *** search
/ Pascal Super Library / Pascal Super Library (CW International)(1997).bin / MLT_TASK / ONCE / ONCE.PAS < prev    next >
Pascal/Delphi Source File  |  1995-02-12  |  19KB  |  560 lines

  1. {************************************************}
  2. {                                                }
  3. {                                                }
  4. {   Copyright(c) by Alan Pozner 1995 all rights  }
  5. {                reserved                        }
  6. {                                                }
  7. {                                                }
  8. {         TITLE : ONCE.PAS                       }
  9. {   CREATE DATE : 1/24/95                        }
  10. {                                                }
  11. {        AUTHOR : Alan Pozner                    }
  12. {                                                }
  13. {                                                }
  14. {                                                }
  15. {      LANGUAGE : Turbo Pascal foe Windows 1.5   }
  16. {      COMPILER : Borland Turbo Pascal 1.5 for   }
  17. {                 Windows                        }
  18. {     CALLED BY : none                           }
  19. {                                                }
  20. {                                                }
  21. {         CALLS : wobjects, winprocs, wintypes,  }
  22. {                        windos, strings, win31,shellapi}
  23. {                 toolhelp                       }
  24. {                                                }
  25. {       PURPOSE : Source code for ONCE.EXE       }
  26. {                 A Windows wrapper program that }
  27. {                 allows only one instance of    }
  28. {                 another application to be run  }
  29. {                 concurrently.                  }
  30. {                                                }
  31. {        USEAGE : A Windows INI file for the     }
  32. {                 program to be protected must be}  
  33. {                 created before using ONCE. Then}
  34. {                 the name of the ini file is    } 
  35. {                 entered as a command line param}
  36. {                 eter.  i.e. for an ini file    }
  37. {                 named DOS.INI the command line }
  38. {                 should read ONCE DOS.INI       }
  39. {                                                }
  40. {                 The format of the ini file is  }
  41. {    [PARAMETERS]                                  }
  42. {  AppFileName=file name of app to run           }
  43. {               - including path                 }
  44. {  AppTitle= the name to appear on the Title bar*}
  45. {  WorkingDir=path for working directory*        }
  46. {  IconFile=file name and path of icon file*     }
  47. {  IconNumber=index of icon in icon file 0=first*}
  48. {                                                }
  49. {* the last four parameters are only required for}
  50. {      DOS apps.                                 }
  51. {  Windows apps ignore them.                     }
  52. {                                                }
  53. {   LAST UPDATE : 2/12/95                        }
  54. {                                                }
  55. {************************************************}
  56.  
  57.  
  58. program Once;
  59.  
  60.  
  61.  
  62. uses wobjects, winprocs, wintypes, windos, strings, shellapi,win31,toolhelp;{standard TPW units}
  63.  
  64.  
  65. {************************************************}
  66. {       Global Constants                         }
  67. {************************************************}
  68.  
  69. const
  70.     ini_name           = 'ONCE.INI';    {INI file name}
  71.  
  72.                                                         {these 2 are for the ini file}
  73.     protected          = 'ProtectedApps';
  74.     filename           = 'FileName';       
  75.     instancehandle     = 'InstanceHandle';
  76.  
  77.                                           {messagebox Messages}
  78.     guide1             = 'OneTime is a program launcher which allows only one instance.';
  79.     guide2             = 'OneTime    Copyright ⌐ 1995 by Alan Pozner';
  80.     guide3             = 'Please read the README.TXT file that accompanies this program for useage';
  81.     loadfail           = 'Loading Failed. Check parameters and filenames';
  82.  
  83.  
  84.  
  85.  
  86. {************************************************}
  87. {       Global Variables                         }
  88. {************************************************}
  89.  
  90. var
  91.     szAppFileName,
  92.     szAppTitle,
  93.     szWorkingDir,
  94.    szIconFile,
  95.     szIniPath,
  96.     szIniName : array[0..79] of char; 
  97.     wIconnumber   : word;
  98.     ProtectedTask,
  99.     ProtectedInstance : THandle;
  100.  
  101.  
  102.  
  103. type
  104. {************************************************}
  105. {       application object type def              }
  106. {************************************************}
  107. OneTimeApp = object(TApplication)
  108.     procedure initmainwindow; virtual;
  109. end;   {OneTimeApp type def
  110.  
  111.  
  112.  
  113.  
  114. {************************************************}
  115. {       main window object type def              }
  116. {************************************************}
  117. pOneTimeWindow = ^TOneTimeWindow;    
  118. TOneTimeWindow = object(Twindow)
  119.     DDEDone   : boolean;           
  120.     constructor init(AParent: PWindowsObject; ATitle: pchar);
  121.     destructor Done; virtual;
  122.     function GetClassName:pchar;virtual;
  123.     procedure SetUpWindow; virtual;
  124.     procedure WMSize(var Msg : TMessage);
  125.         virtual wm_First + wm_size;
  126.     procedure WMTimer(var Msg: TMessage);
  127.       virtual wm_First + wm_timer;
  128.     procedure WMDDEInitiate(var Msg: TMessage);
  129.         virtual wm_First + wm_DDE_Initiate;
  130.     procedure WMDDERequest(var Msg: TMessage);
  131.         virtual wm_First + wm_DDE_Request;
  132. end;  {TOneTimeWindow type def}
  133.  
  134.  
  135. function GetInstanceTask(theInstance:THandle):THandle;
  136. var
  137.     aTaskEntry : pTaskEntry;
  138.    tempTask   : THandle;
  139. begin
  140.     getmem(aTaskEntry,sizeof(TTaskEntry));
  141.     aTaskEntry^.dwSize := sizeof(TTaskEntry);
  142.     taskfirst(aTaskEntry);
  143.     tempTask := 0;
  144.     if aTaskEntry^.hInst = theInstance then
  145.         tempTask := aTaskEntry^.hTask
  146.     else
  147.         while taskNext(aTaskEntry) and (tempTask = 0) do
  148.             if aTaskEntry^.hInst = theInstance then
  149.                 tempTask := aTaskEntry^.hTask;
  150.    GetInstanceTask := tempTask;
  151.     freemem(aTaskEntry,sizeof(TTaskEntry));
  152. end;
  153.  
  154. function GetTaskWindow(theTask:THandle):hwnd;
  155. var
  156.     gotit      : boolean;
  157.    temphwnd   : hwnd;
  158. begin
  159.     gotit := false;
  160.     temphwnd := GetWindow(gettopwindow(0),GW_HWNDLAST);
  161.     while (temphwnd <> 0) and (not gotit)  do
  162.         if (getwindowtask(temphwnd) = theTask) and iswindowvisible(temphwnd) then
  163.             gotit := true
  164.         else
  165.           temphwnd := GetWindow(temphwnd,GW_HWNDPREV);
  166.     GetTaskWindow := temphwnd;
  167. end;
  168.  
  169. function GetTheClassName(Wnd: HWnd;      {this function is necessary because}
  170.                     ClassName: PChar;         {of a name collision between }
  171.                     MaxCount: Integer): Integer; {the API function and the object}
  172. begin                                       {method GetClassName}
  173.     GetTheClassName := GetClassName(Wnd, ClassName, MaxCount);
  174. end;    {GetTheClassName}
  175.  
  176.  
  177. function DumpIcon(lpInfo, lpLen, XORBits, ANDBits : Pointer) : LongInt; far; EXTERNAL 'USER' Index 459;
  178.  
  179. function GetIconData(Icon : hIcon) : THandle;
  180.   type
  181.     PCursorIconInfo = ^CursorIconInfo;
  182.     CursorIconInfo = record
  183.      HotSpot : TPoint;
  184.       Width, Height, WidthBytes : Word;
  185.       Planes, BitsPixel : Byte
  186.       end;
  187.  
  188.     PIconProps = ^TIconProps;
  189.     TIconProps = record
  190.       Flags : Word;
  191.       cfFormat : Integer;
  192.       Width, Height : Integer;
  193.       Planes, BitsPixel : Byte;
  194.       XORbits, ANDbits : Pointer;
  195.     end;
  196.  
  197.   var
  198.      I : PCursorIconInfo;
  199.      P : PIconProps;
  200.      H : THandle;     
  201.      hdrlen : Word;
  202.      pANDBits, pXORBits : Pointer;
  203.      size : Word;
  204.   begin
  205.   I := LockResource(Icon);
  206.   size := HiWord(DumpIcon(I, @HdrLen, @pXORbits, @pANDBits));
  207.   if size <> 0 then
  208.     begin
  209. {the best thing to do here would be to allocate 'size' more bytes here
  210. and copy the data pointed to by pANDBits/pXORBits to the end of the structure,
  211. but this works so I haven't done it yet.}
  212.     H := GlobalAlloc(GMEM_DDESHARE, Sizeof(TIconProps));{ +size);}
  213.     P := GlobalLock(H);
  214.     P^.Width := I^.Width;
  215.     P^.Height := I^.Height;
  216.     P^.Planes := I^.Planes;
  217.     P^.BitsPixel := I^.BitsPixel;
  218.     P^.ANDBits := pANDBits;
  219.     P^.XORBits := pXORBits;
  220.     GlobalUnlock(H);
  221.      UnlockResource(Icon);
  222.     GetIconData := H;
  223.     end
  224.   else
  225.     GetIconData := 0;
  226.   end;
  227. function intostr(buffer: pchar;i:longint) : pchar;
  228. var
  229.       s : string;
  230. begin
  231.       str(i, s);
  232.     strpcopy(buffer,s);
  233.    intostr := buffer;
  234. end;
  235.  
  236.  
  237. {************************************************}
  238. {       Method implementation for                }
  239. {     Procedure OneTimeApp.initmainwindow        }
  240. {                                                }
  241. {     This is the entry point to the program     }
  242. {     after initialization overhead and before   }
  243. {     any windows are created.                   }
  244. {                                                }
  245. {     Command line parameters are checked        }
  246. {     If OK then we check for another instance of}
  247. {     ONETIME. If another instance is found      }
  248. {     we check ONETIME.INI to see if the         }
  249. {     protected app is the same. If so display   }
  250. {     a message and quit. Otherwise we move on   }
  251. {     with loading.  If no command line parameter}
  252. {     display guide  message and quit. If        }
  253. {     no other instance of ONETIME is running    }
  254. {     clean out ONETIME.INI This is necessary    }
  255. {     to avoid lockout in the event of previous  }
  256. {     unusual termination i.e. The user shut     }
  257. {     down without exiting windows.              }
  258. {                                                }
  259. {************************************************}
  260. procedure OneTimeApp.initmainwindow;
  261. var
  262.     sztemp,
  263.     WindowsDir : array[0..79] of char;
  264.     oldwindowhandle : hwnd;
  265.     oldTaskHandle,
  266.     oldInstanceHandle : tHandle;
  267.     tempi,
  268.     code :integer;
  269. begin
  270.     GetWindowsDirectory(WindowsDir,79);
  271.     strcat(strcat(strcopy(szIniPath,
  272.                 WindowsDir),'\'),ini_name);
  273.     if paramcount > 0 then                   {if there is a command line}
  274.                                                           {    parameter}
  275.     begin
  276.         strpcopy(szIniName,paramstr(1));  {load 1st parameter}
  277.  
  278.         if HPrevInst = 0 then                 {if this is only ONETIME instance}
  279.         begin
  280.             _lclose(_lcreat(szIniPath,0));            {erase old INI file}
  281.         end;
  282.         GetPrivateProfileString('Parameters','AppFileName',
  283.                                         '',szAppFileName,sizeof(szAppFileName),
  284.                               szIniName);
  285.         GetPrivateProfileString('Parameters','AppTitle',
  286.                                         '',szAppTitle,sizeof(szAppTitle),
  287.                               szIniName);
  288.         GetPrivateProfileString('Parameters','WorkingDir',
  289.                                         '',szWorkingDir,sizeof(szWorkingDir),
  290.                               szIniName);
  291.         GetPrivateProfileString('Parameters','IconFile',
  292.                                         '',szIconFile,sizeof(szIconFile),
  293.                               szIniName);
  294.         wIconNumber := GetPrivateProfileInt('Parameters',
  295.                                     'IconNumber', 0, szIniName);
  296.         if GetPrivateProfileInt(              {if this app is not protected}
  297.                 Protected,               
  298.                 szAppFileName,0,
  299.                 szIniPath) = 0 then              {then}
  300.         begin
  301.             WritePrivateProfileString(         {protect it by loading name in INI}
  302.              Protected,szAppFileName,        {file}
  303.                 '1',szIniPath);                  {and}
  304.             mainwindow := new(pOneTimeWindow,  {start up main window which will }
  305.                 init(nil,'Main Window'));       {load the app and install hooks}
  306.         end
  307.         else                                  {else this app is protected so}
  308.         begin
  309.             GetPrivateProfileString(szAppFileName,InstanceHandle,
  310.                                         '',szTemp,sizeof(szTemp),
  311.                               szIniPath);
  312.             val(sztemp,tempi,code);
  313.             if code = 0 then
  314.             begin
  315.                 oldinstancehandle := thandle(tempi);
  316.                 oldtaskhandle := GetInstanceTask(oldinstanceHandle);
  317.                 oldwindowhandle := GetTaskWindow(oldtaskhandle);
  318.                 if iswindow(oldwindowhandle) then
  319.                 begin
  320.                     setactivewindow(oldwindowhandle);
  321.                     GetModuleFileName(oldinstancehandle,sztemp,79);
  322.                if strpos(sztemp,'.MOD') = nil then
  323.                         showwindow(oldwindowhandle,SW_SHOW)
  324.                     else
  325.                         showwindow(oldwindowhandle,SW_SHOWNORMAL);
  326.                 end;
  327.             end;
  328.             halt;                              {and quit}
  329.         end;                                  {end 'if this app isn't protected'}
  330.     end
  331.     else                                     {else there are no command line }
  332.     begin                                    {parameters}
  333.         messagebeep(0);
  334.         messagebox(0,guide1,guide2,           {so display useage guide}
  335.                 mb_ok or mb_systemmodal);
  336.         messagebox(0,guide3,guide2,
  337.                 mb_ok or mb_systemmodal);
  338.         halt;                                 {and quit}
  339.     end;                                                  {end 'if there's parameters}
  340.  
  341. end;          {OneTimeApp.initmainwindow}
  342.  
  343.  
  344.  
  345. constructor TOneTimeWindow.init(AParent: PWindowsObject; ATitle: pchar);
  346. begin
  347.     TWindow.init(AParent,Atitle);
  348.     with Attr do
  349.     begin
  350.         x:= -100;
  351.         y:= -100;
  352.         w:= 10;
  353.         h:= 10;
  354.     end;
  355. end;
  356.  
  357. {************************************************}
  358. {       Method implementation for                }
  359. {     Procedure TOneTimeWindow.SetUpWindow       }
  360. {                                                }
  361. {     SetUpWindow procedure is called by Windows }
  362. {     immediately after window initialization    }
  363. {                                                }
  364. {     If we get this far it means that the       }
  365. {     protected app is not running.              }
  366. {                                                }
  367. {     We try to set the Hook. If unsuccessful    }
  368. {     give the user a message to contact MIS     }
  369. {                                                }
  370. {     If the hook is set we make a call to       }
  371. {     WINEXEC to start the app. If successful    }
  372. {     protect app by modifying INI file.         }
  373. {     If unsuccessful loading then remove app    }
  374. {     protection from INI file, display an error }
  375. {     message and quit.                          }
  376. {                                                }
  377. {************************************************}
  378. procedure TOneTimeWindow.SetUpWindow;
  379. var
  380.    instancename,
  381.     afilename : array[0..79] of char;
  382.     tempword : word;
  383. begin
  384.    DDEDone := false;
  385.     ProtectedInstance := winexec(             {try to start app}
  386.         szAppFileName,SW_SHOWNORMAL);
  387.     if ProtectedInstance < 32 then            {if starting failed}
  388.     begin
  389.         WritePrivateProfileString(               {unprotect the app by }
  390.             Protected,szAppFileName,           {removing name from INI file}
  391.             nil,szIniPath);                     {and}
  392.         messagebeep(0);
  393.         messagebox(hwindow,                   {display error message}
  394.             LoadFail,szAppFileName, mb_OK or mb_iconexclamation);
  395.         postmessage(hwindow,wm_close,0,0);      {quit this app}
  396.       exit;
  397.     end;                                     {end 'if loadinf failed}
  398.     GetModuleFileName(ProtectedInstance,afilename,79);
  399.     WritePrivateProfileString(
  400.         szAppFileName,FileName,aFileName,szIniPath);
  401.     intostr(instancename,ProtectedInstance);
  402.     WritePrivateProfileString(
  403.         szAppFileName,InstanceHandle,instancename,szIniPath);
  404.     if SetTimer(HWindow, 1, 1000, nil) = 0 then
  405.    begin
  406.         MessageBox(HWindow, 'No Timers Left', 'Error', mb_Ok);
  407.           Halt(1);
  408.       end;
  409. end;      {TOneTimeWindow.SetUpWindow}
  410.  
  411. procedure TOneTimeWindow.WMSize(var Msg : TMessage);
  412. begin
  413.     Show(sw_hide);                           {hide this window}
  414.     twindow.wmsize(msg);                     {on startup}
  415. end;      {TOneTimeWindow.WMSize}
  416.  
  417.  
  418. procedure TOneTimeWindow.WMTimer(var Msg: TMessage);
  419. begin
  420.     if GetInstanceTask(ProtectedInstance)=0 then
  421.     begin
  422.         killtimer(hwindow,1);
  423.         postmessage(hwindow,wm_close,0,0);      {quit this app}
  424.     end;
  425. end;
  426.  
  427. procedure TOneTimeWindow.WMDDEInitiate(var Msg: TMessage);
  428. var
  429.    szTopic,
  430.     szApp:array[0..127] of char;
  431. begin
  432.     if (not DDEDone) then
  433.     begin
  434.         GlobalGetAtomName(TAtom(LoWord(Msg.Lparam)),szApp,sizeof(szApp)-1);
  435.         GlobalGetAtomName(TAtom(HiWord(Msg.Lparam)),szTopic,sizeof(szTopic)-1);
  436.         if (stricomp(szApp,'shell')=0) and (stricomp(szTopic,'APPPROPERTIES')=0) then
  437.             sendmessage(msg.wparam,WM_DDE_ACK,hwindow,msg.lparam)
  438.         else
  439.           defwndproc(msg)
  440.     end
  441.     else
  442.         defwndproc(msg);
  443. end;
  444.  
  445. procedure TOneTimeWindow.WMDDERequest(var Msg: TMessage);
  446. const
  447.     fRelease = $4;  {this doesn't seem to work}
  448. var
  449.    szTopic,
  450.     szApp:array[0..127] of char;
  451.     counter : integer;
  452.     AppTopic : TAtom;
  453.     HData : THandle;
  454.     PData : PDDEData;
  455.     DataError : boolean;
  456.     anicon:hicon;
  457.    picon : pointer;
  458. begin
  459.     if (not DDEDone) then
  460.     begin
  461.         AppTopic := TAtom(HiWord(Msg.Lparam));
  462.         GlobalGetAtomName(AppTopic,szTopic,sizeof(szTopic)-1);
  463.         if stricomp(szTopic,'GetDescription') = 0 then
  464.         begin
  465.             HData := GlobalAlloc(gmem_Moveable or gmem_DDEShare,
  466.                             sizeof(TDDEData) + strlen(szAppTitle) +1);
  467.             if HData <> 0 then
  468.             begin
  469.                 PData := GlobalLock(HData);
  470.                 if PData = nil then
  471.                 begin
  472.                     GlobalFree(HData);
  473.                     DataError := true;
  474.                 end
  475.                 else
  476.                 begin
  477.                     PData^.Flags := dde_release;
  478.                     PData^.CFFormat := cf_text;
  479.                     strlcopy(PData^.Value, szAppTitle, strlen(szAppTitle)+1);
  480.                     GlobalUnlock(HData)
  481.                 end;
  482.             end;
  483.             if not PostMessage(Msg.WParam, wm_DDE_Data, hwindow,
  484.                                         makelong(HData,AppTopic)) then
  485.                 GlobalFree(HData);
  486.         end
  487.         else
  488.             if stricomp(szTopic,'GetWorkingDir') = 0 then
  489.             begin
  490.                 HData := GlobalAlloc(gmem_Moveable or gmem_DDEShare,
  491.                                 sizeof(TDDEData) + strlen(szWorkingDir) +1);
  492.                 if HData <> 0 then
  493.                 begin
  494.                     PData := GlobalLock(HData);
  495.                     if PData = nil then
  496.                     begin
  497.                         GlobalFree(HData);
  498.                         DataError := true;
  499.                     end
  500.                     else
  501.                     begin
  502.                         PData^.Flags := dde_release;
  503.                         PData^.CFFormat := cf_text;
  504.                         strlcopy(PData^.Value, szWorkingDir,
  505.                                 strlen(szWorkingDir)+1);
  506.                         GlobalUnlock(HData)
  507.                     end;
  508.                 end;
  509.                 if not PostMessage(Msg.WParam, wm_DDE_Data, hwindow,
  510.                                             makelong(HData,AppTopic)) then
  511.                     GlobalFree(HData);
  512.             end
  513.             else
  514.                 if stricomp(szTopic,'GetIcon') = 0 then
  515.                 begin
  516.                     Msg.lParamLo := GetIconData(extracticon(hinstance,
  517.                                         szIconFile,wIconNumber) );
  518.                   pdata := GlobalLock(Msg.lParamLo);
  519.                   with pdata^ do
  520.                   begin
  521.                         Flags := fRelease;
  522.                         cfFormat := CF_TEXT;
  523.                   end;
  524.                   GlobalUnlock(Msg.lParamLo);
  525.                     SendMessage(Msg.wParam, WM_DDE_DATA, hWindow, Msg.lParam);
  526.                   GlobalFree(Msg.lParamLo);
  527.  
  528.                 end;
  529.     end
  530.     else
  531.         defwndproc(msg);
  532. end;
  533.  
  534. destructor TOneTimeWindow.Done;
  535. begin
  536.     WritePrivateProfileString(               {unprotect the app by }
  537.         Protected,szAppFileName,    {removing name from INI file}
  538.         nil,szIniPath);
  539.     WritePrivateProfileString(               {and by removing the app}
  540.         szAppFileName,nil,           {section name from INI file}
  541.         nil,szIniPath);
  542.     TWindow.Done;
  543. end;       {TOneTimeWindow.Done;}
  544.  
  545. function TOneTimeWindow.GetClassName; {give the app unique class name}
  546. var
  547.     paramstring : string;
  548.    sztemp : pchar;
  549. begin
  550.     GetClassName := 'One Time';
  551. end;       {TOneTimeWindow.GetClassName}
  552.  
  553. var
  554.     app: OneTimeApp;
  555. begin
  556.     app.init('One Time');          {normal Windows object Pascal code}
  557.     app.run;                       
  558.    app.done;
  559. end.       {ONETIME.PAS} 
  560.